#if !defined(MAP_FILTER_H_)
#define MAP_FILTER_H_

#include <Eigen/Dense>
#include <memory>
#include <mutex>

namespace autodrive {
namespace perception {
/// @brief declare map
struct Map;
/// @brief declare map filter implementation class
class MapFilterImpl;
/// @brief map filter class
class MapFilter final {
 public:
  MapFilter();
  MapFilter(MapFilter &&) = delete;
  MapFilter(const MapFilter &) = delete;
  MapFilter &operator=(MapFilter &&) = delete;
  MapFilter &operator=(const MapFilter &) = delete;
  ~MapFilter();

 public:
  /// @brief point2f
  struct Point2f {
    /// @brief x
    float x;
    /// @brief y
    float y;
  };

  /// @brief roi
  struct ROI {
    /// @brief point top left
    Point2f top_left;
    /// @brief point bottom right
    Point2f bottom_right;
  };

  /// @brief match parameters
  struct MatchParameter {
    /// @brief match roi
    ROI roi;
    /// @brief match threshold
    float chamfer_distance_threshold;
    /// @brief min distance threshold
    float min_distance_threshold;
    /// @brief outlier distance threshold
    float max_distance_threshold;
  };

  /// @brief fusion parameter
  struct FusionParamter {
    /// @brief fusion lower limit
    float x_low_limit;
    /// @brief fusion threshold
    float threshold;
    /// @brief history weight
    float history_weight;
  };

  /// @brief map filter parameter
  struct MapFilterParameter {
    /// @brief filter roi
    ROI roi;
    /// @brief match parameter
    MatchParameter match_paramemter;
    /// @brief fusion parameter
    FusionParamter fusion_parameter;
    /// @brief life time threshold
    std::int32_t lifetime_threshold;
    /// @brief life time threshold
    std::int32_t lifetime_bonus_threshold;
  };

 public:
  /// @brief init
  /// @param para map filter parameter
  /// @throw
  void Init(MapFilterParameter const &para) noexcept(false);

  /// @brief is init flag
  /// @return init flag
  bool IsInit() noexcept;

  /// @brief do map filter
  /// @param map map data
  /// @param pose current pose
  /// @throw std::runtime_error uninitialized
  /// @throw std::runtime_error predict road edge error
  /// @throw std::runtime_error predict lane divider error
  /// @throw std::runtime_error predict center line error
  void operator()(Map &map, Eigen::Affine3d const &pose) noexcept(false);

 private:
  /// @brief  init call once flag
  mutable std::once_flag init_flag_;
  /// @brief map filter impl pointer
  std::shared_ptr<MapFilterImpl> map_filter_impl_ptr_;
};
}  // namespace perception
}  // namespace autodrive
#endif  // MAP_FILTER_H_